Adding a Command to Ruby
The instructions below detail the steps required to add a Simics runtime command to the Ruby module.
Assumptions
These instructions assume most commands are issued from the ruby/ directory of your workspace. The command added in the example assumes a single string parameter is needed as an agrument to the command.
The final version of the command will look something like this (invokeable from the Simics command line):
ruby0.my-command "my argument"
Command Cookbook
Short Version
- Decide name of command, arguments, etc.
Add an entry for your command to module/commands.py.
Add a RUBY_COMMAND([COMMAND_NAME]) macro in module/ruby.c.
Update module/ruby.c's ruby_session_set() function to check for the new command.
Add a declaration of [FUNCTION_NAME] to simics/commands.h.
Implement [FUNCTION_NAME] in simics/commands.C.
Detailed Version
- Select values for the following "variables" for your command. They will be used throughout this cookbook.
[FUNCTION_NAME]: Name of the function in C++ that your command will invoke. In this example, we use my_command as our [FUNCTION_NAME].
[COMMAND_NAME]: A double-quote encapuslated string, the name of the Simics command. In this example, we use "my-command" as our [COMMAND_NAME].
[ARGUMENT_NAME]: Name of the argument (or arguments) to the command. In this example, we use my_argument as our [ARGUMENT_NAME]. Note that if your command has many arguments, it should have many [ARGUMENT_NAME]s.
[ARGUMENT_DESCRIPTION]: A double-quote encapsulated string, describing the nature of the argument.
[COMMAND_DESCRIPTION_SHORT]: A double-quote encapsulated string, briefly describing the new command.
[COMMAND_DESCRIPTION_LONG]: A double-quote encapsulated string, describing the new command in detail.
Add an entry for your command to module/commands.py. Your entry should be of the form:
1 def [FUNCTION_NAME](obj, [ARGUMENT_NAME]): 2 SIM_set_attribute(obj, [COMMAND_NAME], [ARGUMENT_NAME]) 3 4 new_command([COMMAND_NAME], [FUNCTION_NAME], 5 args = [args(str_t, [ARGUMENT_DESCRIPTION], "?", "")], 6 type = "multifacet commands", 7 namespace = "ruby", 8 short = [COMMAND_DESCRIPTION_SHORT], 9 doc = """ 10 <b>[COMMAND_NAME]</b> [COMMAND_DESCRIPTION_LONG] 11 """)
- For example, if we substitute our "variable" definitions into the python code:
1 def ruby_my_command(obj, my_argument): 2 SIM_set_attribute(obj, "my-command", my_argument) 3 4 new_command("my-command", ruby_my_command, 5 args = [arg(str_t, "a string argument", "?", "")], 6 type = "multifacet commands", 7 namespace = "ruby", 8 short = "a description of the command", 9 doc = """ 10 <b>my-command</b> an example command for the Multifacet WIKI 11 """)
Ruby's module/commands.py should provide examples of how to use parameters.
Add a RUBY_COMMAND([COMMAND_NAME]) macro to the list of RUBY_COMMAND() macros in module/ruby.c. Note that module/ruby.c is a C-language file, not C++, so do not use C++ language components in module/ruby.c.
1 ... 2 RUBY_COMMAND( "abort-all" ); // last command already in ruby.c 3 RUBY_COMMAND( "my-command" ); // entry for the new command 4 ...
Add a check to the long if/else tree in module/ruby.c's ruby_session_set() function, such that if command is identically equal to [COMMAND_NAME], then [FUNCTION_NAME] is called. Again note that module/ruby.c is a C-language file, not C++, so do not use C++ language components in module/ruby.c.
1 ... 2 /* Last currently-existing command */ 3 } else if (!strcmp(command, "tracer-output-file" ) ) { 4 char* new_filename = (char*) val->u.string; 5 ruby_set_tracer_output_file(new_filename); 6 return Sim_Set_Ok; 7 8 /* Entry for the new command*/ 9 } else if (!strcmp(command, "my-command" ) ) { 10 char* my_argument = (char*) val->u.string; 11 12 /* Call [FUNCTION_NAME] now */ 13 ruby_my_command( my_argument ); 14 15 /* Don't forget this line! */ 16 return Sim_Set_Ok; 17 }
Add a declaration of [FUNCTION_NAME] to simics/commands.h.
1 ... 2 /* old commands */ 3 void ruby_set_tracer_output_file (const char * new_filename); 4 5 /* our new command */ 6 void ruby_my_command(const char * my_argument); 7 8 #endif // COMMANDS_H
Add the implementation of the command ([FUNCTION_NAME]) to simics/commands.C. simics/commands.C is a C++ language source file, and therefore you are free to use applicable C++ syntax. You are also free to invoke code elsewhere in Ruby from simics/commands.C. Our example below simply prints the contents of its parameter to the screen.
1 2 /* Be sure to prefix your function name with extern "C" */ 3 extern "C" 4 void ruby_my_command(const char * my_argument) { 5 cout << "My argument was [" << my_argument << "] " << endl; 6 /* 7 * Can make calls to Ruby here, see other functions in 8 * commands.C for examples 9 */ 10 11 return; 12 } 13
- Your command should now be in-place. Recompile Ruby and test your command.